#include "stdafx.h"

#include <string>
#include <iostream>
#include <vector>
#include <limits>

#include "commandLine.h"
#include "menu.h"
#include "Game.h"
#include "basePlayer.h"
#include "baseCard.h"
#include "baseToken.h"
#include "boardEffect.h"
#include "moveInfo.h"

using namespace std;

static void s_Get_PlayerName(string& szPlayerName)
{
    printf("Enter player name: ");
    while (!( cin >> szPlayerName ))
    { 
        if (cin.eof())
            return;
        else if (cin.fail())
        { 
            printf("Invalid Choice, Retry : ");
            cin.clear(); 
        }
        else
            printf("Invalid Choice, Retry : ");
    }
}

static void s_Get_PlayerColor(string& szPlayerColor)
{
    printf("Enter player color: ");
    while (!( cin >> szPlayerColor ))
    { 
        if (cin.eof())
            return;
        else if (cin.fail())
        { 
            printf("Invalid Choice, Retry : ");
            cin.clear(); 
        }
        else
            printf("Invalid Choice, Retry : ");
    }
}

static void s_Print_Directions()
{
    printf(
        "\nDirections:\n"

        "  1 - Up\n"
        "  2 - Down\n"
        "  3 - Left\n"
        "  4 - Right\n"

        "\n");
}

static void s_Get_MoveDirection(int *pDirection)
{
    s_Print_Directions();
    printf("Enter Direction: ");
    fflush(stdout);
    while (!( cin >> *pDirection )|| *pDirection <= 0 || *pDirection > 4)
    { 
        if (cin.eof())
            return;
        else
        { 
            printf("Invalid Choice, Retry : ");
            fflush(stdout);
            if (cin.fail())
            {
                cin.clear();
                cin.ignore( numeric_limits<streamsize>::max(), '\n' );
            }
        }
    }
}

static void s_Get_Col(int* col)
{
    printf("Enter column number: ");
    fflush(stdout);
    while (!( cin >> *col ) || *col <= 0)
    { 
        if (cin.eof())
            return;
        else
        { 
            printf("Invalid Choice, Retry : ");
            fflush(stdout);
            if (cin.fail())
            {
                cin.clear();
                cin.ignore( numeric_limits<streamsize>::max(), '\n' );
            }
        }
    }
}

static void s_Get_Row(int* row)
{
    printf("Enter row number: ");
    fflush(stdout);
    while (!( cin >> *row ) || *row <= 0)
    { 
        if (cin.eof())
            return;
        else
        { 
            printf("Invalid Choice, Retry : ");
            fflush(stdout);
            if (cin.fail())
            {
                cin.clear();
                cin.ignore( numeric_limits<streamsize>::max(), '\n' );
            }
        }
    }
}

static void s_Get_RowCol(int* row, int* col)
{
    s_Get_Row(row);
    s_Get_Col(col);
}

static void s_Get_TokenNumber(int* tempTokenNum)
{
    printf("Enter token number: ");
    fflush(stdout);
    while (!( cin >> *tempTokenNum ) || *tempTokenNum <= 0)
    { 
        if (cin.eof())
            return;
        else
        { 
            printf("Invalid Choice, Retry : ");
            fflush(stdout);
            if (cin.fail())
            {
                cin.clear();
                cin.ignore( numeric_limits<streamsize>::max(), '\n' );
            }
        }
    }
}

namespace cmdlineGame
{
    Game* game;

    void menu_AddPlayers()
    {
        unsigned int selection;
        string pPlayerName;
        string pColor;
        basePlayer* tempPlayer = NULL; 
        unsigned int playerIndex = 1;
        vector<basePlayer*> players;
        int tempTokenNum;

        const char * const xoptions[] = {"Add Player",
                                         "Rename Player",
                                         "Set Token Number",
                                         "Show players"};

        Menu xmenu("CardG Add Players", sizeof(xoptions)/sizeof(char *), xoptions );
        do
        {
            players = game->getPlayers();
            Menu xmenuPlayer("Select a player", players);

            selection = xmenu.getUserSelection();
            /// selectItem
            switch(selection)
            {
                case 1:
                    if(game->countPlayers() < game->getMaxPlayers())
                    {
                        s_Get_PlayerName(pPlayerName);
                        s_Get_PlayerColor(pColor);
                        tempPlayer = new basePlayer(pPlayerName, pColor, game->getBoard(), game->getTokenNumber(), game->getDeck());
                        game->addPlayer(*tempPlayer);
                    }
                    else
                    {
                        cout << "Maximum number of player has been reached" << endl;
                    }
                    break;
                case 2:
                    if(!players.empty())
                    {
                        do
                        {
                            playerIndex = xmenuPlayer.getUserSelection();
                            if (playerIndex != 0 && playerIndex <= players.size())
                            {
                                s_Get_PlayerName(pPlayerName);
                                game->getPlayers()[playerIndex-1]->setName(pPlayerName);
                                break;
                            }
                        } while ( playerIndex != 0 ); 
                    }
                    else
                    {
                        cout << "No player to rename" << endl;
                    }
                    break;
                case 3:
                    s_Get_TokenNumber(&tempTokenNum);
                    game->setTokenNumber(tempTokenNum);
                    break;
                case 4:
                    cout << endl << game->toString();
                    break;
                default:
                    break;
            }
        } while ( selection != 0 );
    }

    int menu_Player_Card(baseCard c)
    {
        unsigned int playerIndex = 1;
        int direction;
        basePlayer* currPlayer = game->getActivePlayer();

        baseEffect* effect = c.getEffect();

        vector<basePlayer*> players = game->getPlayers();
        Menu xmenuPlayer("Select a player", players);

        if(effect)
        {
            switch(effect->getType())
            {
                case baseEffect::board:
                    s_Get_MoveDirection(&direction);
                    if(((boardEffect*)effect)->isRowAllowed()
                       && (direction == 3 || direction == 4))
                    {
                        int tempRow;
                        s_Get_Row(&tempRow);

                        if(tempRow-1 <= game->getBoard()->getHeight())
                        {
                            moveInfo mvInfo((direction==3)?boardEffect::left:boardEffect::right, tempRow-1);
                            
                            effect->doEffect(&mvInfo);
                            game->checkForWonCards();
                            currPlayer->cardPlayed(c);
                            return 1;
                        }
                        else
                            cout << "Invalid row value" << endl;
                        break;
                    }
                    else if(((boardEffect*)effect)->isColAllowed()
                            && (direction == 1 || direction == 2))
                    {
                        int tempCol;
                        s_Get_Col(&tempCol);

                        if(tempCol-1 <= game->getBoard()->getWidth())
                        {
                            moveInfo mvInfo((direction==1)?boardEffect::up:boardEffect::down, tempCol-1);
                            
                            effect->doEffect(&mvInfo);
                            game->checkForWonCards();
                            currPlayer->cardPlayed(c);
                            return 1;
                        }
                        else
                            cout << "Invalid column value" << endl;
                        break;

                    }
                    else
                    {
                        cout << "You can't move in this direction" << endl;
                    }
                    break;
                case baseEffect::deck:
                    break;
                case baseEffect::player:
                    do
                    {
                        playerIndex = xmenuPlayer.getUserSelection();
                        if (playerIndex != 0 && playerIndex <= players.size())
                        {
                            effect->doEffect(game->getPlayers()[playerIndex-1]);
                            currPlayer->cardPlayed(c);
                            return 1;
                        }
                    } while ( playerIndex != 0 );                           
                    break;
                case baseEffect::trash:
                    break;
                default:
                    break;
            }
        }
        else
        {
            cout << "No effect on this card" << endl;
        }

        return 0;
    }

    void menu_Player_Cards()
    {
        unsigned int selection;
        list<baseCard> cardsList;
        cardsList = game->getActivePlayer()->getCardList();
        vector<baseCard> cards(cardsList.begin(), cardsList.end());

        Menu xmenu("Cards", cards);
        do
        {
            selection = xmenu.getUserSelection();
            if (selection != 0 && selection <= cards.size())
            {
                if(menu_Player_Card(cards[selection-1]))
                    return;
            }
        } while ( selection != 0 );
    }


    void menu_LoopPlay()
    {
        unsigned int selection;
        int row = 0;
        int col = 0;
        baseCard* card = NULL;

        if(game
           && game->countPlayers() > 0)
            {
            const char * const xoptions[] = {"Use token",
                                             "Take token",
                                             "Use card effect"};

            Menu xmenu("CardG Add Players", sizeof(xoptions)/sizeof(char *), xoptions );
            do
            {
                game->checkForWonCards();
                // Draw everything
                game->display();

                selection = xmenu.getUserSelection();
                // selectItem
                switch(selection)
                {
                    case 1:
                        s_Get_RowCol(&row, &col);
                        if(col-1 <= game->getBoard()->getWidth()
                           && row-1 <= game->getBoard()->getHeight())
                        {
                            card = game->getBoard()->getCard(col-1, row-1);

                            if(card != NULL)
                                game->getActivePlayer()->useToken(*card);
                            else
                                cout << "No card here..." << endl;
                        }
                        else
                            cout << "Invalid row or column value" << endl;
                        break;
                    case 2:
                        s_Get_RowCol(&row, &col);
                        if(col-1 <= game->getBoard()->getWidth()
                           && row-1 <= game->getBoard()->getHeight())
                        {
                            card = game->getBoard()->getCard(col-1, row-1);

                            if(card != NULL)
                            {
                                if(card->countTokens(game->getActivePlayer()->getColor()) > 0)
                                    game->getActivePlayer()->takeToken(*card);
                                else
                                    cout << "You can't take a token from this card" << endl;
                            }
                            else
                                cout << "No card here..." << endl;
                        }
                        else
                            cout << "Invalid row or column value" << endl;
                        break;
                    case 3:
                        if(game->getActivePlayer()->getCardList().size() > 0)
                        {
                            menu_Player_Cards();
                        }
                        else
                            cout << "You don't have any card" << endl;
                        break;
                    default:
                        break;
                }
            } while ( selection != 0 );
        }
        else
        {
            cout << "No player. Add players first." << endl;
        }
    }

    void menu_Game()
    {    
        unsigned int selection;

        const char * const xoptions[] = {"Player Management",
                                          "Start Game"};

        Menu xmenu("CardG menu", sizeof(xoptions)/sizeof(char *), xoptions );
        do
        {
            selection = xmenu.getUserSelection();
            /// selectItem
            switch(selection)
            {
                case 1:
                    menu_AddPlayers();
                   break;
                case 2:
                   menu_LoopPlay();
                   break;
                default:
                    break;
            }
        } while ( selection != 0 );
    }
}

/***************************************
 *  EnterCommandLine
 *  entry point for comand line testing
 ***************************************/

void enterCommandLine(baseBoard* board, baseDeck* deck, baseDeck* trash)
{
    Game* game = new Game(board, deck, trash);

    cmdlineGame::game = game;
    cmdlineGame::menu_Game();

    if(game != NULL)
    {
        delete game;
        game = NULL;
    }
}
